using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using EntLibContrib.PolicyInjection.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection;
using System.Reflection;
using System.Threading;

namespace EntLibContrib.PolicyInjection.CallHandlers
{
    /// <summary>
    /// An <see cref="ICallHandler"/> that queues the call to the next handler on the ThreadPool.
    /// </summary>
    /// <remarks>Only supported for methods that have void as their return type. Otherwise, the handler will have no effect.</remarks>
    [ConfigurationElementType(typeof(OneWayCallHandlerData))]
    public class OneWayCallHandler : ICallHandler
    {
        #region ICallHandler Members

        /// <summary>
        /// Processes the method call.
        /// </summary>
        /// <remarks>This handler queues the call to next handler on the ThreadPool</remarks>
        /// <param name="input"><see cref="IMethodInvocation"/> with information about the call.</param>
        /// <param name="getNext">delegate to call to get the next handler in the pipeline.</param>
        /// <returns>Return value from the target.</returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn result = null;

            if (TargetMethodReturnsVoid(input))
            {
                ThreadPool.QueueUserWorkItem(delegate(object notUsed)
                {
                    getNext()(input, getNext);
                });

                result = input.CreateMethodReturn(null);
            }
            else
            {
                result = getNext()(input, getNext);
            }

            return result;
        }

        #endregion

        private bool TargetMethodReturnsVoid(IMethodInvocation input)
        {
            MethodInfo targetMethod = input.MethodBase as MethodInfo;
            return targetMethod != null && targetMethod.ReturnType == typeof(void);
        }
    }
}
